
import annotation.XmlClosure;
import annotation.XmlEntity;
import constant.XmlConstant;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Features: XML工具方法
 * @Date:
 * @Author: hihuzi  2018/6/18 11:51
 */

public class XmlUtil implements XmlFactory {

    /**
     * TODO XML 转换成 String 生成器
     *
     * @Author:hihuzi 2018/6/20 8:59
     */
    @Override
    public String getXml(List list) throws Exception {

        StringBuffer XML = new StringBuffer();
        XML.append(XmlConstant.Title.getValue());
        return getXml(list, XmlConstant.SIGN.getValue(), XML);
    }

    /**
     * TODO XML 转换成 对象 解析器
     * 处理规则xml
     *
     * @Author:hihuzi 2018/6/20 8:59
     */
    @Override
    public <T> List<T> getXml(String XML, T t) throws Exception {

        return getXml(XML, t, XmlConstant.Title);
    }


    // TODO 实现方法

    // tips 实现方法
    private static <T> List<T> getXml(String XML, T t, XmlConstant xmlConstant) throws Exception {
        // tips 思路
        List<T> result = new ArrayList<T>();
        Class<?> clazz = t.getClass();
        List<String> isAnnotation = new ArrayList<>();//tips 单行属性
        Map fieldsMap = new HashMap();//存储 直接属性
        Map annotationfieldsMap = new HashMap();//存储 属性的子属性
        Field[] fields = clazz.getDeclaredFields();
        //tips 取出所有字段
        if (clazz.isAnnotationPresent(XmlEntity.class)) {
            for (Field field : fields) {
                if (field.isAnnotationPresent(XmlClosure.class))
                    fieldsMap.put(field.getName(), field.getAnnotation(XmlClosure.class).name());
                else
                    fieldsMap.put(field.getName(), field.getName());
                if (field.isAnnotationPresent(XmlClosure.class)) {//处理属性上有注解
                    if (field.getAnnotation(XmlClosure.class).isLonely()) {
                        for (String parameter : field.getAnnotation(XmlClosure.class).attributes()) {
                            isAnnotation.add(parameter);//注入注解字段
                        }
                    }
                }
            }
        }
        Iterator fieldsmaps = fieldsMap.entrySet().iterator();
        while (fieldsmaps.hasNext()) {
            Map.Entry entry = (Map.Entry) fieldsmaps.next();
            String key0 = entry.getKey().toString();
            String key1 = entry.getValue().toString();
            if (isAnnotation.contains(key0)) {
                annotationfieldsMap.put(key0, key1);
            }
        }
        Iterator key = annotationfieldsMap.keySet().iterator();
        while (key.hasNext()) {
            fieldsMap.remove(key.next());
        }

        //tips 开始取值
        Element root = DocumentHelper.parseText(XML).getRootElement();
        List<Element> elements = root.elements();
        for (Element element : elements) {
            Object obj = t.getClass().newInstance();/*新建对象*/
            Iterator iterator = annotationfieldsMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry) iterator.next();
                String key3 = String.valueOf(entry.getKey());
                String values = String.valueOf(entry.getValue());
                StringBuffer name = new StringBuffer();
                name.append("set").append(key3.substring(0, 1).toUpperCase()).append(key3.substring(1));
                String value = null;/*头下属性*/
                try {
                    value = element.attributeValue(values);
                } catch (Exception e) {
                }
                if (value != null) {
                    Class<?> paramtertype = clazz.getDeclaredField(key3).getType();
                    setParamter(obj, name.toString(), value, paramtertype);
                }
            }
            Iterator iterators = fieldsMap.entrySet().iterator();
            while (iterators.hasNext()) {
                Map.Entry entry = (Map.Entry) iterators.next();
                String key4 = String.valueOf(entry.getKey());
                String values = String.valueOf(entry.getValue());
                StringBuffer name = new StringBuffer();
                name.append("set").append(key4.substring(0, 1).toUpperCase()).append(key4.substring(1));
                String value = null;/*头下属性*/
                try {
                    value = element.element(values).getStringValue();
                } catch (Exception e) {
                }
                if (value != null) {
                    Class<?> paramtertype = clazz.getDeclaredField(key4).getType();
                    setParamter(obj, name.toString(), value, paramtertype);
                }

            }
            result.add((T) obj);
        }
        return result;
    }

    public static String getXml(List list, String sign, StringBuffer XML) throws Exception {


        StringBuffer xml = XML;
        for (Object entity: list) {
            Class clazz = entity.getClass();
            /*当前对象*/
            Object newEntity = entity;
            /*结束标签*/
            List<String> temporaryDeposits = new ArrayList<>();
            List<String> exclude = new ArrayList<>();
            String property = "";
            Field[] fields = clazz.getDeclaredFields();
            List<String> notAnontationfields = new ArrayList(fields.length);
            Boolean isHavingEndTag = ((XmlEntity) clazz.getAnnotation(XmlEntity.class)).isHavingEndTag();//类

            if (clazz.isAnnotationPresent(XmlEntity.class)) {
                for (Field field: fields) {
                    //TODO 第一层
                    if (field.isAnnotationPresent(XmlClosure.class)) {
                        /*排除已经备用的属性*/
                        exclude.add(field.getName());
                        XmlClosure XmlClosure = field.getAnnotation(XmlClosure.class);
                        temporaryDeposits.add(XmlClosure.name());
                        xml.append("<" + XmlClosure.name());
                        for (String parameter: XmlClosure.attributes()) {
                            /*排除已经备用的属性*/
                            exclude.add(parameter);
                            property = String.valueOf(getProperty(clazz, newEntity, parameter));
                            xml.append(" " + parameter + "=\"" + property + "\"");
                        }
                        xml.append(">");
                    } else {
                        //TODO 提高效率 添加list 备用
                        notAnontationfields.add(field.getName());
                    }
                }
                //TODO 清除已经被使用的 属性
                notAnontationfields.removeAll(exclude);
                //TODO 第二层 没有注解的处理
                for (String parameter: notAnontationfields) {
                    /*排除是集合的属性*/
                    if (("String".equals(clazz.getDeclaredField(parameter).getType().getSimpleName()))) {
                        if (!isHavingEndTag) {
                            xml.append("<" + parameter + ">");
                            property = String.valueOf(getProperty(clazz, newEntity, parameter));
                            xml.append("\"" + property + "\"");
                            xml.append("</" + parameter + ">");
                        } else {
                            xml.append("<" + parameter + " " + sign + "=");
                            property = String.valueOf(getProperty(clazz, newEntity, parameter));
                            xml.append("\"" + property + "\"");
                            xml.append("/>");
                        }
                    } else {
                        //TODO 添加 一个结束标签
                        for (int i = temporaryDeposits.size() - 1; i > 0; i--) {
                            xml.append("</" + temporaryDeposits.get(i) + ">");
                            temporaryDeposits.remove(temporaryDeposits.get(i));
                            break;
                        }
                        //TODO 没有注解是 LIST 处理
                        List sonList = (List) getProperty(clazz, newEntity, parameter);
                        //TODO 重复调用
                        getXml(sonList, sign, xml);
                    }
                }

                for (int i = temporaryDeposits.size() - 1; i >= 0; i--) {
                    xml.append("</" + temporaryDeposits.get(i) + ">");
                }
            }
        }
        return xml.toString();
    }


    // TODO 公共方法

    public static Object getProperty(Class clazz, Object newEntity, String parameter) throws Exception {

        Object property;
        StringBuffer key = new StringBuffer();
        key.append("get").append(parameter.substring(0, 1).toUpperCase()).append(parameter.substring(1));
        property = clazz.getMethod(key.toString(), new Class[]{}).invoke(newEntity);
        return property;
    }

    private static <T> void setParamter(Object object, String name, String value, Class<?> paramtertype) throws Exception {

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
        Method method = object.getClass().getMethod(name, paramtertype);
        if (null != value && !"".equals(value)) {
            if ("String".equals(paramtertype.getSimpleName())) {
                method.invoke(object, value);
            } else if ("Date".equals(paramtertype.getSimpleName())) {
                Date temp = simpleDateFormat.parse(value);
                method.invoke(object, temp);
            } else if ("Integer".equals(paramtertype.getSimpleName())
                    || "int".equals(paramtertype.getSimpleName())) {
                Integer intval = Integer.parseInt(value);
                method.invoke(object, intval);
            } else if ("Long".equalsIgnoreCase(paramtertype.getSimpleName())) {
                Long temp = Long.parseLong(value);
                method.invoke(object, temp);
            } else if ("Double".equalsIgnoreCase(paramtertype.getSimpleName())) {
                Double temp = Double.parseDouble(value);
                method.invoke(object, temp);
            } else if ("Boolean".equalsIgnoreCase(paramtertype.getSimpleName())) {
                Boolean temp = Boolean.parseBoolean(value);
                method.invoke(object, temp);
            } else if ("BigDecimal".equalsIgnoreCase(paramtertype.getSimpleName())) {
                BigDecimal temp = new BigDecimal(value);
                method.invoke(object, temp);
            } else {
                System.out.println("类型错误" + paramtertype.getSimpleName());
            }
        }
    }

}
/*思路2  效率低*/
//            for (Field field: fields) {
//                field.setAccessible(true);
//                //TODO 第二层 除去被提升为行内的
//                if (!field.isAnnotationPresent(XmlClosure.class) && !exclude.contains(field.getName())) {
//                    String parameter = field.getName();
//                    //TODO 既没有注解也不是List
//                    if (!clazz.getDeclaredField(parameter).getType().getName().equals("java.util.List")) {
//                        xml.append("<" + field.getName() + " " + sig + "=");
//                        property = String.valueOf(getProperty(clazz, newEntity, parameter));
//                        xml.append("\"" + property + "\"");
//                        xml.append("/>");
//                    } else {
//                        //TODO 添加 一个结束标签
//                        for (int i = temporaryDeposits.size(); i > 0; i--) {
//                            xml.append("</" + temporaryDeposits.get(i - 1).substring(0, 1).toUpperCase() + temporaryDeposits.get(i - 1).substring(1) + ">");
//                            temporaryDeposits.remove(temporaryDeposits.get(i - 1));
//                            break;
//                        }
//                        //TODO 没有注解是 LIST 处理
//                        List sonList = (List) getProperty(clazz, newEntity, parameter);
//                        //TODO 重复调用
//                        getXml(sonList, sig, xml);
//                    }
//                }
//            }